package com.ddone.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
 * @author ddone
 * @date 2024/4/5-14:16
 */
@Configuration
@Slf4j
public class RabbitMqPublisherConfig {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    // 创建Topic类型的交换机
    @Bean
    public TopicExchange demoExchange() {
        return ExchangeBuilder
                .topicExchange("demo.exchange")
                .durable(true)
                // 配置持久化
                .ignoreDeclarationExceptions()
                // 忽略声明时的异常
                .build();
    }


    @Bean
    public TopicExchange orderExchange() {
        return ExchangeBuilder
                .topicExchange("order.exchange.biz")
                .durable(true)
                .ignoreDeclarationExceptions()
                .build();
    }


    // 声明死信交换机
    @Bean
    public TopicExchange deadExchange(){
        return ExchangeBuilder
                .topicExchange("dead.exchange")
                .durable(true)
                .ignoreDeclarationExceptions()
                .build();
    }

    // 声明死信队列
    @Bean
    public Queue deadQueue(){
        return QueueBuilder
                .durable("dead-queue")
                .deadLetterExchange("delay.exchange")
                .deadLetterRoutingKey("msg.delay")
                .ttl(600000)
                .build();
    }

    // 绑定死信队列和交换机
    @Bean
    public Binding deadBinding(TopicExchange deadExchange,Queue deadQueue){
        return BindingBuilder
                .bind(deadQueue)
                .to(deadExchange)
                .with("msg.dead");
    }

    @Bean
    public Queue demoQueue() {
        return QueueBuilder
                .durable("demo.queue")
                // 创建持久化的队列
                .build();
    }

    @Bean
    public Queue orderQueue(){
        return QueueBuilder
                .durable("order.queue.biz")
                .deadLetterExchange("dead.exchange")
                .deadLetterRoutingKey("msg.dead")
                .build();
    }



    @Bean
    public Binding demoQueueBinding(TopicExchange demoExchange, @Qualifier("demoQueue") Queue  demoQue) {
        return BindingBuilder
                .bind(demoQue)
                .to(demoExchange)
                .with("a.#");
    }

    @Bean
    public Binding orderQueueBinding(TopicExchange orderExchange,Queue orderQueue){
        return BindingBuilder
                .bind(orderQueue)
                .to(orderExchange)
                .with("order.pay");
    }

    // 延迟队列

    @Bean
    public TopicExchange delayExchange(){
        return ExchangeBuilder
                .topicExchange("delay.exchange")
                .durable(true)
                .ignoreDeclarationExceptions()
                .build();
    }

    @Bean
    public Queue delayQueue(){
        return QueueBuilder
                .durable("delay.queue")
                .build();
    }

    @Bean
    public Binding delaBinding(Queue delayQueue,TopicExchange delayExchange){
        return BindingBuilder
                .bind(delayQueue)
                .to(delayExchange)
                .with("msg.delay");
    }

    @PostConstruct
    // 初始化
    public void init() {
        // 确认消息是否到达交换机
        this.rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
                    if (!ack) {
                        log.warn("消息没有到达交换机: " + cause);
                    }
                });
        // 发送消息失败 回调中可以尝试重新发送mq消息

        // 但是开发中不会重发:

        // 原因1 rabbit mq 性能稳定失败概率低, 原因2: 性能差 一般保存日志 手动处理
        // 确认消息是否到达队列，到达队列该方法不执行
        this.rabbitTemplate.setReturnCallback((message,replyCode,replyText,exchange,routingKey) -> {
            log.warn("消息没有到达队列,来自于交换机: {}, 路由键: {}, 消息内容: {}",exchange,routingKey,new String(message.getBody()));
        });
    }

}
